﻿using System.Collections.Concurrent;
using HelenServer.FileStorage.Contracts;
using HelenServer.Grpc.Contracts;

namespace HelenServer.FileStorage.Services;

[Injection(typeof(IFSMigrateSpider))]
internal class FSMigrateSpider :
    GrpcMethod<int, GrpcResult<IReadOnlyDictionary<int, int[]>>>, IFSMigrateSpider
{
    private readonly IFileStorateMigrateQueueProvider _provider;
    private readonly IFileStorageService _service;
    private readonly HttpClient _httpClient;

    public FSMigrateSpider(IFileStorateMigrateQueueProvider provider, IFileStorageService service, HttpClient httpClient)
    {
        _provider = provider;
        _service = service;
        _httpClient = httpClient;
    }

    public override async Task<GrpcResult<IReadOnlyDictionary<int, int[]>>> InvokeAsync(int request, ServerCallContext context)
    {
        _httpClient.DefaultRequestHeaders.Add("Authorization", context.RequestHeaders.GetString("zt_authorization"));

        var box = new Dictionary<int, ConcurrentBag<UploadModel>>();
        var resultBox = new List<KeyValuePair<int, int[]>>();

        try
        {
            var idx = 0;
            while (!_provider.Queue.IsEmpty)
            {
                if (_provider.Queue.TryDequeue(out var job))
                {
                    box.Add(job.Key, new ConcurrentBag<UploadModel>());

                    foreach (var spider in job.Value)
                    {
                        var buffer = await _httpClient.GetByteArrayAsync(spider.Url, context.CancellationToken);

                        var model = new UploadModel
                        {
                            Name = spider.Name,
                            Extension = spider.Extension,
                            AddedBy = spider.AddedBy,
                            Buffer = buffer,
                        };

                        box[job.Key].Add(model);
                    }

                    idx++;
                }

                if (idx >= 500)
                {
                    var operation = context.GetHttpContext().GetOperation(box.Select(n => new KeyValuePair<int, IEnumerable<UploadModel>>(n.Key, n.Value.ToList().AsEnumerable())));

                    var result = await _service.UploadFileRangeForMigrateAsync(operation, context.CancellationToken);

                    resultBox.AddRange(result.Data);

                    idx = 0;

                    box.Values.ToList().ForEach(n => n.Clear());
                    box.Clear();
                    GC.Collect();
                }
            }

            return OperationResult<IReadOnlyDictionary<int, int[]>>.OK(resultBox.ToDictionary(k => k.Key, v => v.Value)).ToGrpcResult(r => r);
        }
        catch (Exception)
        {

            throw;
        }
    }
}